// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-7-15


//#include ".\config.h"

// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-5-21

#include "stdafx.h"
#pragma push_macro("new")
#undef new
#include ".\jzip.h"
#include ".\tool\bzlib.h"
#include <vector>
#pragma pop_macro("new")
#include "windows.h"

// class zip_file

bool zip_file::read(void* buf, size_t len)
{
    size_t readed;
    if(!read(buf, len, readed) || readed != len)
    {
        return false;
    }
    return true;
}

bool zip_file::read_str(string& str)
{
    WORD len;
    if(!read(&len, sizeof(len)))
    {
        return false;
    }
    str.resize(len);
    if(!read(&*str.begin(), len))
    {
        return false;
    }
    return true;
}

bool zip_file::write_str(const string& str)
{
    WORD len = (WORD)str.size();
    if(!write(&len, sizeof(len)))
    {
        return false;
    }
    if(!write(&*str.begin(), len))
    {
        return false;
    }
    return true;
}

// class zip_pkg

zip_pkg::zip_pkg(zip_file*f)
{
    m_file = f;
	
	
}

zip_pkg::~zip_pkg()
{
    
}

void ZipShowError(const char* msg, ...)
{
    va_list args;
    va_start(args, msg);
    char m[512];
    vsprintf(m, msg, args);
    MessageBox(NULL, m, "Error", MB_OK);
	va_end(args);
}
bool zip_pkg::AppendUnZipLength(DWORD len)
{  
   bool succeed=true;
   if(!m_file->write(&len,sizeof(len)))
		succeed=false;
   
 
   return succeed;
   

}
bool zip_pkg::append(const char* path, const char* relPath)
{
    try
    {  
	   
        if(relPath == NULL)
        {
           relPath = path;
        }
		
        if(!m_file->write_str(relPath))
		{
		    ZipShowError("Cannot write file <%s>'s relPath to zip file.", path);
            return false;
		}

        FILE_TIME getFileTime;
		if(!GetFTime(path,getFileTime))
		{
			ZipShowError("Cannot get time of the file <%s>.", relPath);
            return false;
		}

		CFile f;
		if(!f.Open(path, CFile::OpenFlags::modeRead))
		    return false;

		if(!m_file->write(&getFileTime,sizeof(FILE_TIME)))
		{
		    ZipShowError("Cannot write file <%s>'s time to zip file.", path);
            return false;
		}

        size_t len = (size_t)f.GetLength();
        if(!m_file->write(len))
        {
            ZipShowError("Cannot write file <%s>'s length to zip file.", path);
            return false;
        }
        BYTE buf[1024];
        while(len > 0)
        {
            size_t rlen;
            rlen = len > sizeof(buf) ? sizeof(buf) : len;
            if(rlen != f.Read(buf, (UINT)rlen))
            {
                ZipShowError("Failed to read file <%s>.", path);
                return false;
            }
            if(!m_file->write(buf, rlen))
            {
                ZipShowError("Failed to write file <%s> to zip file.", path);
                return false;
            }
            len -= rlen;
        }
        return true;
    }
    catch(...)
    {
        ZipShowError("Cannot append file <%s>.", path);
        return false;
    }
	
}

inline bool is_sep(char c)
{
    return c == '\\' || c == '/';
}

void split_path(const char* path, vector<string>& result, bool full)
{
    result.clear();

    const char* s = path;
    for(; *path != '\0'; ++path)
    {
        if(is_sep(*path))
        {
            if(path > s)
            {
                result.push_back(string(s, path-s));
            }
            if(!full)
            {
                s = path + 1;
            }
        }
    }
}
bool zip_pkg::GetUnZipLength(DWORD &len)
{
	bool succeed=true;
    
	if(!m_file->read(&len,sizeof(len)))
	     succeed=false;
    
    return succeed;

}
bool zip_pkg::extract(const char* dir)
{
    string path;
    char rootDir[MAX_PATH*2];
	FILE_TIME setFileTime;
    size_t rootLen = strlen(dir);
    memcpy(rootDir, dir, rootLen);
    if(!is_sep(rootDir[rootLen-1]))
    {
        rootDir[rootLen] = '\\';
        rootLen ++;
    }
	
	while(m_file->read_str(path))
    {
		m_file->read(&setFileTime,sizeof(FILE_TIME));   
		size_t flen;
        if(!m_file->read(flen))
        {
            ZipShowError("Cannot read length of file <%s> from zip packge.", path.c_str());
            return false;
        }
        
        vector<string> paths;
        split_path(path.c_str(), paths, true);
        int c = (int)paths.size();
        for(int i = 0; i < c; ++ i)
        {
            strcpy(rootDir+rootLen, paths[i].c_str());
            DWORD dwAttrib = GetFileAttributes(rootDir);
            if(dwAttrib == INVALID_FILE_ATTRIBUTES)
            {
                if(!::CreateDirectory(rootDir, NULL))
                {
                    ZipShowError("Can not create Directory <%s> .", rootDir);
                    return false;
				}
            }
          
        }
		 
        try
        {
           strcpy(rootDir+rootLen, path.c_str());
		   ::DeleteFile(rootDir);
		    CFile f(rootDir, CFile::OpenFlags::modeCreate|CFile::OpenFlags::modeWrite);
            BYTE buf[4096];
            while(flen > 0)
            {
                size_t wlen = flen>sizeof(buf) ? sizeof(buf) : flen;
                if(!m_file->read(buf, wlen))
                {
                    ZipShowError("Failed to read from pakage.");
                    return false;
                }
                try
                {
                    f.Write(buf, (UINT)wlen);
				}
                catch(...)
                {
                    ZipShowError("Failed to write to file <%s>.", rootDir);
                    return false;
                }

                flen -= wlen;
            }
			f.Close();
			if(!SetFTime(rootDir,setFileTime))
			{
			    ZipShowError("Cannot write file <%s>'s time.", path);
                return false;
			}
        }
        catch(...)
        {
            ZipShowError("Cannot create file <%s>.", rootDir);
            return false;
        }
		
    }
    return true;
}

// class bzip2_file

bzip2_file::bzip2_file()
{
    m_data  = NULL;
}

bzip2_file::~bzip2_file()
{
    close();
}

bool bzip2_file::open(const char* path, bool writable)
{
    m_data  = BZ2_bzopen(path, writable ? "w" : "r");
    if(m_data == NULL)
    {
        return false;
    }
    return true;
}

void bzip2_file::close()
{
    if(m_data == NULL)
    {
        return;
    }
    BZ2_bzclose(m_data);
    m_data = NULL;
}

bool bzip2_file::read(void* buf, size_t len, size_t& readed)
{
    int r = BZ2_bzread(m_data, buf, (int)len);
    int err;
    BZ2_bzerror(m_data, &err);
    switch(err)
    {
    case BZ_STREAM_END:
    case BZ_OK:
        readed = r;
        return true;
    default:
        readed = 0;
        return false;
    }
}

bool bzip2_file::write(const void* buf, size_t len)
{
    size_t r = BZ2_bzwrite(m_data, (void*)buf, (int)len);
    if(r != len)
    {
        return false;
    }
    return true;
}

bool zip_pkg::GetFTime(const char* path, FILE_TIME &ftime)
{  
	CFile f(path,CFile::modeRead);
	if (f.m_hFile == NULL)
		return false;
    CFileStatus fileStatus;
    if(!f.GetStatus(fileStatus))
	{
		f.Close();
		return false;
	}
	f.Close();

	ftime.creationTime=fileStatus.m_ctime;
	ftime.lastAccessTime=fileStatus.m_atime;
	ftime.lastWriteTime=fileStatus.m_mtime;
	
	return true;
}
bool zip_pkg::SetFTime(const char *path, FILE_TIME &ftime)
{
    CFile f(path, CFile::OpenFlags::modeRead);
	if(f.m_hFile == NULL)
		return false;
	CFileStatus fileStatus;
	f.GetStatus(fileStatus);
	f.Close();
    
    
	
	
	fileStatus.m_ctime=ftime.creationTime;
	fileStatus.m_atime=ftime.lastAccessTime;
	fileStatus.m_mtime=ftime.lastWriteTime;
	CFile::SetStatus(path,fileStatus);
	
	return true;
}

